package com.showtao.front.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.showtao.common.enumeration.EErrorCode;
import com.showtao.common.exception.BizServiceException;
import com.showtao.front.domain.Product;
import com.showtao.front.domain.ProductCategory;
import com.showtao.front.domain.Tag;
import com.showtao.front.domain.VehicleModel;
import com.showtao.front.domain.VehicleModelFeature;
import com.showtao.front.dto.ProductDto;
import com.showtao.front.dto.SearchResultItemDto;
import com.showtao.front.dto.upstream.ProductCategorySavingDto;
import com.showtao.front.dto.upstream.ProductSavingDto;
import com.showtao.front.repository.ProductCategoryRepository;
import com.showtao.front.repository.ProductRepository;
import com.showtao.front.repository.ResourceRepository;
import com.showtao.front.repository.TagRepository;
import com.showtao.front.repository.VehicleModelFeatureRepository;
import com.showtao.front.repository.VehicleModelRepository;

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private ProductCategoryRepository productCategoryRepository;
    @Autowired
    private VehicleModelRepository vehicleModelRepository;
    @Autowired
    private VehicleModelFeatureRepository vehicleModelFeatureRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private ResourceService resourceService;
    @Autowired
    private TagRepository tagRepository;

    @Transactional(readOnly = true)
    @Cacheable(value = "productByModelAndCategory", key = "'MODEL-' + #id + ';CATEGORY-' + #category")
    public Object[] findProductsByModelAndCategory(Long id, String category) {
    	Object[] result = new Object[2];
    	VehicleModel model = vehicleModelRepository.getOne(id);
        ProductCategory productCategory = productCategoryRepository.getByCode(category);
        Set<Product> products = productRepository.findByModelAndCategory(model, productCategory);
        Map<String, List<VehicleModelFeature>> map = new HashMap<String, List<VehicleModelFeature>>();
        for(Product p: products){
        	if(p!=null && p.getFeatures()!=null){
        		List<VehicleModelFeature> vmfs = p.getFeatures();
        		for(VehicleModelFeature vmf : vmfs){
        			if (!StringUtils.isBlank(vmf.getCategoryNumber())) {
                        List<VehicleModelFeature> list = map.get(vmf.getCategoryNumber());
                        if (list == null) {
                        	list = new ArrayList<VehicleModelFeature>();
                            map.put(vmf.getCategoryNumber(), list);
                        }
                        if(!list.contains(vmf)){
                        	list.add(vmf);
                        }
                    }
        		}
        	}
        }
        result[0] = products;
        result[1] = map;
        return result;
    }

    @Transactional(readOnly = true)
    @Cacheable(value = "allProductCategories")
    public List<ProductCategory> findAllProductCategories() {
        return new ArrayList<ProductCategory>(productCategoryRepository.findAll());
    }

    @Transactional(readOnly = true)
    @Cacheable(value = "featuresByModel", key = "'MODEL-' + #id")
    public Map<String, List<VehicleModelFeature>> findFeaturesByModel(Long id) {
        Map<String, List<VehicleModelFeature>> map = new HashMap<String, List<VehicleModelFeature>>();
        VehicleModel model = vehicleModelRepository.getOne(id);
        Set<VehicleModelFeature> features = vehicleModelFeatureRepository.findByModel(model);
        for (VehicleModelFeature feature : features) {
            if (!StringUtils.isBlank(feature.getCategoryNumber())) {
                List<VehicleModelFeature> list = map.get(feature.getCategoryNumber());
                if (list == null) {
                    list = new ArrayList<VehicleModelFeature>();
                    map.put(feature.getCategoryNumber(), list);
                }
                list.add(feature);
            }
        }
        return map;
    }

    @Transactional(readOnly = true)
    public Product getOneJoinCategory(Long id) {
        return productRepository.getOneJoinCategory(id);
    }
    
    @Transactional(readOnly = true)
    public Product getOneJoinFully(Long id) {
        return productRepository.getOneJoinFully(id);
    }
    
    @Transactional(readOnly = true)
    public Product getProductByCode(String code) {
    	return productRepository.getProductByCode(code);
    }

    @Transactional(readOnly = true)
    public ProductCategory getProductCategoryByCode(String code) {
        return productCategoryRepository.getByCode(code);
    }
    

    @Transactional(readOnly = true)
    public List<Product> findLimitedProductAccordingTo(String keywords, String category, int size) {
        Pageable pageable = new PageRequest(0, size);
        Page<Product> products = productRepository.findByCategoryAndCodeLike(category, keywords, pageable);
        return products.getContent();
    }

    @Transactional(readOnly = true)
    public List<SearchResultItemDto> findSearchTips(String keywords, String category) {
        Pageable pageable = new PageRequest(0, 5);
        Page<VehicleModel> vms = vehicleModelRepository.findByNameLike(keywords, pageable);
        Page<Product> products = productRepository.findByCategoryAndCodeLike(category, keywords, pageable);
        List<SearchResultItemDto> items = new ArrayList<SearchResultItemDto>();
        for (VehicleModel vm : vms) {
            SearchResultItemDto item = new SearchResultItemDto();
            item.setId(vm.getId());
            StringBuilder sb = new StringBuilder();
            if (vm.getLine() != null) {
                sb.append(vm.getLine().getName()).append(" - ");
            }
            sb.append(vm.getName());
            item.setName(sb.toString());
            item.setType("vm");
            items.add(item);
        }
        for (Product product : products) {
            SearchResultItemDto item = new SearchResultItemDto();
            item.setId(product.getId());
            StringBuilder sb = new StringBuilder();
            if (product.getModel() != null) {
                if (product.getModel().getLine() != null) {
                    sb.append(product.getModel().getLine().getName()).append(" - ");
                }
                item.setParentId(product.getModel().getId());
                sb.append(product.getModel().getName()).append(" - ");
            }
            sb.append(product.getCode());
            item.setName(sb.toString());
            item.setType("pd");
            items.add(item);
        }
        return items;
    }

    @Transactional(readOnly = true)
    public Page<ProductCategory> findProductCategories(Pageable pageable) {
        return productCategoryRepository.findAll(pageable);
    }

    @Transactional
    @CacheEvict(value = "allProductCategories")
    public void saveProductCategory(ProductCategorySavingDto dto) {
        ProductCategory entity = null;
        boolean isNew = false;
        if ( dto.getId() != null) {
            entity = productCategoryRepository.getOne(dto.getId());
            if (entity == null) {
                throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR, "找不到ID=" + dto.getId()
                        + "的ProductCategory实体");
            }
        } else {
        	isNew = true;
            entity = new ProductCategory();
            entity.setCreatedAt(Calendar.getInstance().getTime());
        }
        entity.setName(dto.getName());
        entity.setCode(dto.getCode());
        entity.setUpdatedAt(Calendar.getInstance().getTime());
        productCategoryRepository.save(entity);
        
        if(isNew){
            Tag tag = tagRepository.getByAlias(entity.getCode()+"_summary");
            if(tag == null){
                tag = new Tag();
                tag.setAlias(entity.getCode()+"_summary");
                tag.setName(entity.getName()+"概要");
                tag.setCreatedAt(Calendar.getInstance().getTime());
                tagRepository.save(tag);
            }
        }
    }

    @Transactional
    @CacheEvict(value = "allProductCategories")
    public void deleteProductCategory(Long id) {
        productCategoryRepository.delete(id);
    }

    @Transactional(readOnly = true)
    public Page<ProductDto> findProducts(Pageable pageable) {
        Page<Product> page = productRepository.findAllJoinFully(pageable);
        List<ProductDto> list = new ArrayList<ProductDto>();
        for (Product pd : page) {
            list.add(ProductDto.from(pd));
        }
        return new PageImpl<ProductDto>(list, pageable, page.getTotalElements());
    }

    @Transactional
    public void deleteProduct(Long id) {
        productRepository.delete(id);
    }

    @Transactional
    public void saveProduct(ProductSavingDto dto) {
        Product entity = null;
        VehicleModel model = null;
        ProductCategory category = null;
        if ( dto.getId() != null ) {
            entity = productRepository.getOne(dto.getId());
            if (entity == null) {
                throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR, "找不到ID=" + dto.getId() + "的Product实体");
            }
        } else {
            entity = new Product();
            entity.setCreatedAt(Calendar.getInstance().getTime());
        }
        if ( dto.getModelId() != null) {
            model = vehicleModelRepository.findOne(dto.getModelId());
            if (model == null) {
                throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR, "找不到ID=" + dto.getModelId()
                        + "的VehicleModel实体");
            }
        }
        if ( dto.getCategoryId() != null ) {
            category = productCategoryRepository.findOne(dto.getCategoryId());
            if (category == null) {
                throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR, "找不到ID=" + dto.getModelId()
                        + "的ProductCategory实体");
            }
        }
        if (StringUtils.isNotBlank(dto.getMobileIntroPicResourceId())) {
            entity.setMobileIntroPic(resourceService.saveFromResId(dto.getMobileIntroPicResourceId()));
        }
        
        if (StringUtils.isNotBlank(dto.getIntroPicResourceId())) {
            entity.setIntroPic(resourceService.saveFromResId(dto.getIntroPicResourceId()));
        }
        if (StringUtils.isNotBlank(dto.getMergingPicResourceId())) {
            entity.setMergingPic(resourceService.saveFromResId(dto.getMergingPicResourceId()));
        }
        if (StringUtils.isNotBlank(dto.getParamPicResourceId())) {
            entity.setParamPic(resourceService.saveFromResId(dto.getParamPicResourceId()));
        }
        if (StringUtils.isNotBlank(dto.getDismountingPicResourceId())) {
        	entity.setDismountingPic(resourceService.saveFromResId(dto.getDismountingPicResourceId()));
        }
        entity.setModel(model);
        entity.setCategory(category);
        entity.setCode(StringUtils.trim(dto.getCode()));
        entity.setBoxingQuantity(dto.getBoxingQuantity());
        entity.setHasBackSide(dto.getHasBackSide());
        entity.setHasSpecialNotes(dto.getHasBackSide());
        entity.setHasStereotype(dto.getHasStereotype());
        entity.setHasWalkingBox(dto.getHasWalkingBox());
        entity.setDismountingNotes(dto.getDismountingNotes());
        entity.setModelFactor(dto.getModelFactor());
        entity.setModelParameters(dto.getModelParameters());
        entity.setModelYear(dto.getModelYear());
        entity.setNotes(dto.getNotes());
        entity.setParameters(dto.getParameters());
        entity.setSewingTechnology(dto.getSewingTechnology());
        entity.setBoxingQuantity(dto.getBoxingQuantity());
        entity.setTemplateFeature(dto.getTemplateFeature());
        entity.setUpdatedAt(Calendar.getInstance().getTime());
        entity = productRepository.save(entity);

        // update the features associations
        entity.setFeatures(new ArrayList<VehicleModelFeature>());
        if(dto.getFeatureIds()!=null){
            for (Long id : dto.getFeatureIds()) {
                VehicleModelFeature vmf = vehicleModelFeatureRepository.getOne(id);
                if (vmf != null) {
                    entity.getFeatures().add(vmf);
                }
            }
        }
        productRepository.save(entity);
    }

    // @Transactional(readOnly = true)
    // public Product findOne(String id) {
    // return productJpaRepository.findOne(id);
    // }
    //
    // @Transactional
    // public void save(Product product) {
    // productJpaRepository.save(product);
    // }
    //
    // @Transactional
    // public void delete(String id) {
    // productJpaRepository.delete(id);
    // }
    //
    // @Transactional(readOnly = true)
    // public DataTablesResponseDto<Product> getPageableProduct(
    // final ProductSearchDto searchDto) {
    // Pageable pageRequest = buildPageRequest(searchDto);
    //
    // Specification<Product> specification = new Specification<Product>() {
    // @Override
    // public Predicate toPredicate(Root<Product> root,
    // CriteriaQuery<?> query, CriteriaBuilder cb) {
    // Predicate predicate = cb.conjunction();
    // List<Expression<Boolean>> expressions = predicate
    // .getExpressions();
    //
    // if (searchDto != null) {
    // if (StringUtils.isNotBlank(searchDto.getKeyword())) {
    // expressions.add(cb.or(cb.like(
    // cb.lower(root.<String> get("name")), "%"
    // + searchDto.getKeyword().trim()
    // .toLowerCase() + "%"), cb.like(
    // cb.lower(root.<String> get("description")), "%"
    // + searchDto.getKeyword().trim()
    // .toLowerCase() + "%"), cb.like(
    // cb.lower(root.<String> get("avatarPath")), "%"
    // + searchDto.getKeyword().trim()
    // .toLowerCase() + "%")));
    // }
    // }
    // return predicate;
    // }
    // };
    //
    // Page<Product> products = productJpaRepository.findAll(specification,
    // pageRequest);
    //
    // DataTablesResponseDto<Product> responseDtoList = new DataTablesResponseDto<Product>();
    // List<Product> itemList = new ArrayList<Product>();
    // responseDtoList.setEcho(searchDto.getEcho());
    // for (Product product : products) {
    // itemList.add(product);
    // }
    // responseDtoList.setData(itemList);
    // responseDtoList.setTotalDisplayRecords(products.getTotalElements());
    // responseDtoList.setTotalRecords(products.getTotalElements());
    // return responseDtoList;
    // }
    //
    // private Pageable buildPageRequest(DataTablesRequestDto requestDto) {
    // Sort sort = null;
    // List<Integer> sortedColumns = requestDto.getSortedColumns();
    // List<String> sortDirections = requestDto.getSortDirections();
    // List<String> dataProps = requestDto.getDataProps();
    //
    // if (sortedColumns != null) {
    // for (Integer item : sortedColumns) {
    // String sortColumn = dataProps.get(item);
    // int indexOf = 0;
    // if (StringUtils.isNotBlank(sortColumn)
    // && sortColumn.endsWith(".text")) {
    // indexOf = sortColumn.lastIndexOf(".text");
    // } else if (StringUtils.isNotBlank(sortColumn)
    // && sortColumn.endsWith(".fullText")) {
    // indexOf = sortColumn.lastIndexOf(".fullText");
    // }
    // if (indexOf > 0) {
    // sortColumn = sortColumn.substring(0, indexOf);
    // }
    // String sortDir = sortDirections.get(0);
    // sort = new Sort(Direction.fromString(sortDir), sortColumn);
    // sort = sort.and(new Sort(Direction.fromString(sortDir), "id"));
    // }
    // }
    // PageRequest page = new PageRequest(requestDto.getDisplayStart()
    // / requestDto.getDisplayLength(), requestDto.getDisplayLength(),
    // sort);
    // return page;
    // }

}
